// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// g [author] rhyme_lph
// E [email]  rhymelph@gmail.com
// o [github] https://github.com/rhymelph

import 'dart:async';

import 'package:base_plugin/base_plugin.dart';
import 'package:dio/src/response.dart';
import 'package:finance_app/src/entities/product_entity.dart';
import 'package:finance_app/src/http_service/http_product_service.dart';
import 'package:finance_app/src/mixin/filter_product_service_sort_mixin.dart';
import 'package:finance_app/src/mixin/format_group_map_mixin.dart';
import 'package:finance_app/src/mixin/refresh_mixin.dart';
import 'package:finance_app/src/mixin/search_data_list_mixin.dart';
import 'package:finance_app/src/provider/dashboard/products_services/products_and_services_provider.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/reg_exp_utils.dart';
import 'package:flutter/material.dart';

class ProductsProvider extends BaseProvider<List<ProductEntity>>
    with
        SearchDataListMixin,
        FilterProductServiceSortMixin<List<ProductEntity>>,
        RefreshMixin<List<ProductEntity>, List<ProductEntity>>,
        FormatGroupMapLocalMixin<ProductEntity> {
  bool isSelectMode = false;

  Set<String> filterSet = {};

  bool isShowZero = false;
  ScrollController controller = ScrollController();

  @override
  void initState() {
    super.initState();
    controller.addListener(() {
      getParentProvider<ProductsAndServicesProvider>()
          .handleScrollUpdate(controller);
    });
  }

  @override
  Future get dataFuture => HttpProductService.productList();

  ProductEntity currentSelectContact;

  void onShowAddProductName(String text) async {
    searchFocusNode.unfocus();
    final result =
        await Routes.navigateTo(RouterGenProviders.newProductPage, params: {
      'text': text,
      'isPro': isSelectMode != true,
    });
    if (result != null) {
      data.add(result);
      transformData(data, false);
      _onSelectProduct(result);
    }
  }

  void onShowAddProduct() async {
    searchFocusNode.unfocus();
    final result =
        await Routes.navigateTo(RouterGenProviders.newProductPage, params: {
      'isPro': true,
    });
    if (result != null) {
      data.add(result);
      transformData(data, false);
      _onSelectProduct(result);
    }
  }

  void _onSelectProduct(ProductEntity value) async {
    if (isSelectMode == true) {
      currentSelectContact = value;
      update();
      obtainContext?.call((context) {
        Routes.navigateTo(RouterGenProviders.quantityPage, params: {
          'product': value,
          'usePurchasePrice':
              getParentProvider<ProductsAndServicesProvider>().usePurchasePrice,
        });
        // Navigator.of(context).pop(value);
      });
    } else {
      final result = await Routes.navigateTo(RouterGenProviders.newProductPage,
          params: {'data': value, 'isPro': true});
      if (result != null && result is! ProductEntity && result['delete']) {
        data.remove(value);
        transformData(data, false);
        update();
      }
    }
  }

  void updateProduct(ProductEntity product) {
    final result = data.firstWhere((element) => element.id == product.id,
        orElse: () => null);
    if (result != null) {
      result.fromJson(product.toJson());
    } else {
      data.add(product);
    }
    transformData(data, false);
    update();
  }

  @override
  FutureOr<List<ProductEntity>> transformData(
      List<ProductEntity> d, bool isCache) {
    filterSet.clear();
    d.forEach((element) {
      if (element.categories != null) filterSet.addAll(element.categories);
    });
    groupMap.clear();
    contactToMap(d);
    return d;
  }

  void onSelectProduct(ProductEntity data) {
    if (currentSelectContact == data) return;
    _onSelectProduct(data);
  }

  @override
  List<ProductEntity> get dataList => data;

  @override
  List<ProductEntity> getFromRequestResult(
      Response<dynamic> result, bool isRefresh) {
    List<ProductEntity> data = getEntityFromResult<List<ProductEntity>>(result);
    transformData(data, false);
    return data;
  }

  void contactToMap(List<ProductEntity> contacts) {
    sortGroupToMap(contacts,
        sort: (a, b) {
          if (a.name.length > 0 &&
              b.name.length > 0 &&
              a.name[0] == b.name[0]) {
            if ((a.categories?.length ?? 0) == 0 &&
                (b.categories?.length ?? 0) == 0) {
              return sortName(a, b, (t) => t.name);
            } else if ((a.categories?.length ?? 0) == 0) {
              return 1;
            } else if ((b.categories?.length ?? 0) == 0) {
              return 0;
            }
          }
          return sortName(a, b, (t) => t.name);
        },
        filter: _onFilter,
        group: (a) => groupFirstName(a, (t) => t.name));
  }

  @override
  Future get refreshFuture => dataFuture;

  @override
  void onRequestRefresh() {
    transformData(data, false);
  }

  @override
  void searchRefreshData(searchData) {
    transformData(data, false);
    update();
  }

  bool _onFilter(ProductEntity a) {
    if (isShowZero != true &&
        isSelectMode == true &&
        a?.enableInventory == 1 &&
        a?.inventoryLeft == 0) {
      print('过滤');
      return false;
    }
    if (RegExpUtils.getSearchRegExp(searchController.text).hasMatch(a.name)) {
      bool isFilterStatus = true;
      if (currentSelectActive == 'Active') {
        isFilterStatus = a.isActivated == 1;
      } else if (currentSelectActive == 'Inactive') {
        isFilterStatus = a.isActivated == 0;
      }
      if (currentSelectFilterList.length == 0) {
        return isFilterStatus;
      }
      if (isFilterStatus) {
        if (a.categories != null && a.categories.length > 0) {
          for (final value in (a.categories)) {
            if (currentSelectFilterList.contains(value)) {
              return true;
            }
          }
          return false;
        } else {
          return currentSelectFilterList.contains(noCategory);
        }
      } else {
        return false;
      }
    }
    return false;
  }

  String noCategory = 'No Category Tagged';

  @override
  List<String> get filterDataList {
    List<String> data = filterSet.toList();
    data.sort((a, b) => a.compareTo(b));
    return data..add(noCategory);
  }

  @override
  Future<void> onSelectActive() async {
    await super.onSelectActive();
    onChangeMenuList();
  }

  void onChangeMenuList() {
    final pro = getParentProvider<ProductsAndServicesProvider>();
    if (currentSelectActive == 'Inactive') {
      pro.menuList = ['Activate', 'Delete'];
    } else if (currentSelectActive == 'Active') {
      pro.menuList = [
        'Deactivate',
        'Delete',
        'Adjust Inventory',
      ];
    } else {
      pro.menuList = ['Activate', 'Deactivate', 'Delete', 'Adjust Inventory'];
    }
    pro.update();
  }

  void batchUpdate(List<ProductEntity> entities) {
    for (final item in entities) {
      final entity = data.firstWhere((element) => element.id == item.id,
          orElse: () => null);
      if (entity != null) {
        entity.fromJson(item.toJson());
      }
    }
    transformData(data, false);
    update();
  }
}
